home *** CD-ROM | disk | FTP | other *** search
/ Dr. Windows 3 / dr win3.zip / dr win3 / PROGRAMR / GSRC208A.ZIP / MEM.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  15KB  |  711 lines

  1. /*_ mem.c   Fri Jan 26 1990   Modified by: Walter Bright */
  2. /* Memory management package                            */
  3.  
  4. #define MEM_DEBUG 1
  5.  
  6. #include        <stdio.h>
  7.  
  8. #if __ZTC__
  9. #include        <stdlib.h>
  10. #include        <io.h>
  11. #else
  12. extern void *malloc();
  13. extern void *calloc();
  14. extern void *realloc();
  15. #endif
  16.  
  17. #ifndef MEM_H
  18. #include        "mem.h"
  19. #endif
  20.  
  21. #ifndef assert
  22. #include        <assert.h>
  23. #endif
  24.  
  25. #if MSC
  26. #include        <dos.h>
  27. #endif
  28.  
  29. #ifndef VAX11C
  30. #ifdef BSDUNIX
  31. #include <strings.h>
  32. #else
  33. #include <string.h>
  34. #endif
  35. #else
  36. extern char *strcpy(),*memcpy();
  37. extern int strlen();
  38. #endif  /* VAX11C */
  39.  
  40. int mem_inited = 0;             /* != 0 if initialized                  */
  41.  
  42. static int mem_behavior = MEM_ABORTMSG;
  43. static int (*fp) P((void)) = NULL;      /* out-of-memory handler        */
  44. static int mem_count;           /* # of allocs that haven't been free'd */
  45. static int mem_scount;          /* # of sallocs that haven't been free'd */
  46.  
  47. /* Determine where to send error messages       */
  48. #if MSDOS
  49. #define ferr    stdout  /* stderr can't be redirected with MS-DOS       */
  50. #else
  51. #define ferr    stderr
  52. #endif
  53.  
  54. /*******************************/
  55.  
  56. void mem_setexception(flag,handler_fp)
  57. #if __ZTC__ && __cplusplus
  58. enum MEM_E flag;
  59. #else
  60. int flag;
  61. #endif
  62. int (*handler_fp) P((void));
  63. {
  64.     mem_behavior = flag;
  65.     fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;
  66. #if MEM_DEBUG
  67.     assert(0 <= flag && flag <= MEM_RETRY);
  68. #endif
  69. }
  70.  
  71. /*************************
  72.  * This is called when we're out of memory.
  73.  * Returns:
  74.  *      1:      try again to allocate the memory
  75.  *      0:      give up and return NULL
  76.  */
  77.  
  78. static int near mem_exception()
  79. {   int behavior;
  80.  
  81.     behavior = mem_behavior;
  82.     while (1)
  83.     {
  84.     switch (behavior)
  85.     {
  86.         case MEM_ABORTMSG:
  87. #if MSDOS || __OS2__
  88.         /* Avoid linking in buffered I/O */
  89.         {   static char msg[] = "Fatal error: out of memory\r\n";
  90.  
  91.         write(1,msg,sizeof(msg) - 1);
  92.         }
  93. #else
  94.         fputs("Fatal error: out of memory\n",ferr);
  95. #endif
  96.         /* FALL-THROUGH */
  97.         case MEM_ABORT:
  98.         exit(EXIT_FAILURE);
  99.         /* NOTREACHED */
  100.         case MEM_CALLFP:
  101.         assert(fp);
  102.         behavior = (*fp)();
  103.         break;
  104.         case MEM_RETNULL:
  105.         return 0;
  106.         case MEM_RETRY:
  107.         return 1;
  108.         default:
  109.         assert(0);
  110.     }
  111.     }
  112. }
  113.  
  114. /****************************/
  115.  
  116. #if MEM_DEBUG
  117.  
  118. #undef mem_strdup
  119.  
  120. #if PROTOTYPING
  121. char *mem_strdup(const char *s)
  122. #else
  123. char *mem_strdup(s)
  124. const char *s;
  125. #endif
  126. {
  127.     return mem_strdup_debug(s,__FILE__,__LINE__);
  128. }
  129.  
  130. char *mem_strdup_debug(s,file,line)
  131. char *file;
  132. const char *s;
  133. int line;
  134. {
  135.     char *p;
  136.  
  137.     p = s
  138.         ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
  139.         : NULL;
  140.     return p ? strcpy(p,s) : p;
  141. }
  142. #else
  143. #if PROTOTYPING
  144. char *mem_strdup(const char *s)
  145. #else
  146. char *mem_strdup(s)
  147. const char *s;
  148. #endif
  149. {
  150.     char *p;
  151.  
  152.     p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL;
  153.     return p ? strcpy(p,s) : p;
  154. }
  155.  
  156. #endif /* MEM_DEBUG */
  157.  
  158. #ifdef MEM_DEBUG
  159.  
  160. static long mem_maxalloc;       /* max # of bytes allocated             */
  161. static long mem_numalloc;       /* current # of bytes allocated         */
  162.  
  163. #define BEFOREVAL       0x12345678      /* value to detect underrun     */
  164. #define AFTERVAL        0x87654321      /* value to detect overrun      */
  165.  
  166. #if SUN || SUN386
  167. static long afterval = AFTERVAL;        /* so we can do &afterval       */
  168. #endif
  169.  
  170. /* The following should be selected to give maximum probability that    */
  171. /* pointers loaded with these values will cause an obvious crash. On    */
  172. /* Unix machines, a large value will cause a segment fault.             */
  173. /* MALLOCVAL is the value to set malloc'd data to.                      */
  174.  
  175. #if MSDOS || __OS2__
  176. #define BADVAL          0xFF
  177. #define MALLOCVAL       0xEE
  178. #else
  179. #define BADVAL          0x7A
  180. #define MALLOCVAL       0xEE
  181. #endif
  182.  
  183. /* Disable mapping macros       */
  184. #undef  mem_malloc
  185. #undef  mem_calloc
  186. #undef  mem_realloc
  187. #undef  mem_free
  188.  
  189. /* Create a list of all alloc'ed pointers, retaining info about where   */
  190. /* each alloc came from. This is a real memory and speed hog, but who   */
  191. /* cares when you've got obscure pointer bugs.                          */
  192.  
  193. static struct mem_debug
  194. {       struct mh
  195.     { struct mem_debug *Mnext;      /* next in list                 */
  196.       struct mem_debug *Mprev;      /* previous value in list       */
  197.       char *Mfile;          /* filename of where allocated          */
  198.       int Mline;            /* line number of where allocated       */
  199.       unsigned Mnbytes;     /* size of the allocation               */
  200.       long Mbeforeval;      /* detect underrun of data              */
  201.     } m;
  202.     char data[1];           /* the data actually allocated          */
  203. } mem_alloclist =
  204. {
  205.    {    (struct mem_debug *) NULL,
  206.     (struct mem_debug *) NULL,
  207.     "noname",
  208.     11111,
  209.     0,
  210.     BEFOREVAL
  211.    },
  212.    AFTERVAL
  213. };
  214.  
  215. /* Convert from a void *to a mem_debug struct.  */
  216. #define mem_ptrtodl(p)  ((struct mem_debug *) ((char *)p - sizeof(struct mh)))
  217.  
  218. /* Convert from a mem_debug struct to a mem_ptr.        */
  219. #define mem_dltoptr(dl) ((void *) &((dl)->data[0]))
  220.  
  221. #define next            m.Mnext
  222. #define prev            m.Mprev
  223. #define file            m.Mfile
  224. #define line            m.Mline
  225. #define nbytes          m.Mnbytes
  226. #define beforeval       m.Mbeforeval
  227.  
  228. /*****************************
  229.  * Set new value of file,line
  230.  */
  231.  
  232. void mem_setnewfileline(ptr,fil,lin)
  233. void *ptr;
  234. char *fil;
  235. int lin;
  236. {
  237.     struct mem_debug *dl;
  238.  
  239.     dl = mem_ptrtodl(ptr);
  240.     dl->file = fil;
  241.     dl->line = lin;
  242. }
  243.  
  244. /****************************
  245.  * Print out struct mem_debug.
  246.  */
  247.  
  248. static void near mem_printdl(dl)
  249. struct mem_debug *dl;
  250. {
  251.     fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n",
  252.         dl->file,dl->line,dl->nbytes,(long)mem_dltoptr(dl));
  253. }
  254.  
  255. /****************************
  256.  * Print out file and line number.
  257.  */
  258.  
  259. static void near mem_fillin(fil,lin)
  260. char *fil;
  261. int lin;
  262. {
  263.     fprintf(ferr,"File '%s' line %d\n",fil,lin);
  264.     fflush(ferr);
  265. }
  266.  
  267. /****************************
  268.  * If MEM_DEBUG is not on for some modules, these routines will get
  269.  * called.
  270.  */
  271.  
  272. void *mem_calloc(u)
  273. unsigned u;
  274. {
  275.     return mem_calloc_debug(u,__FILE__,__LINE__);
  276. }
  277.  
  278. void *mem_malloc(u)
  279. unsigned u;
  280. {
  281.     return mem_malloc_debug(u,__FILE__,__LINE__);
  282. }
  283.  
  284. void *mem_realloc(p,u)
  285. void *p;
  286. unsigned u;
  287. {
  288.     return mem_realloc_debug(p,u,__FILE__,__LINE__);
  289. }
  290.  
  291. void mem_free(p)
  292. void *p;
  293. {
  294.     mem_free_debug(p,__FILE__,__LINE__);
  295. }    
  296.  
  297.  
  298. /**************************/
  299.  
  300. void mem_freefp(p)
  301. void *p;
  302. {
  303.     mem_free(p);
  304. }
  305.  
  306. /***********************
  307.  * Debug versions of mem_calloc(), mem_free() and mem_realloc().
  308.  */
  309.  
  310. void *mem_malloc_debug(n,fil,lin)
  311. unsigned n;
  312. char *fil;
  313. int lin;
  314. {   void *p;
  315.  
  316.     p = mem_calloc_debug(n,fil,lin);
  317.     if (p)
  318.     memset(p,MALLOCVAL,n);
  319.     return p;
  320. }
  321.  
  322. void *mem_calloc_debug(n,fil,lin)
  323. unsigned n;
  324. char *fil;
  325. int lin;
  326. {
  327.     struct mem_debug *dl;
  328.  
  329.     do
  330.     dl = (struct mem_debug *)
  331.         calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1);
  332.     while (dl == NULL && mem_exception());
  333.     if (dl == NULL)
  334.     {
  335. #if 0
  336.     printf("Insufficient memory for alloc of %d at ",n);
  337.     mem_fillin(fil,lin);
  338.     printf("Max allocated was: %ld\n",mem_maxalloc);
  339. #endif
  340.     return NULL;
  341.     }
  342.     dl->file = fil;
  343.     dl->line = lin;
  344.     dl->nbytes = n;
  345.     dl->beforeval = BEFOREVAL;
  346. #if SUN || SUN386 /* bus error if we store a long at an odd address */
  347.     memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
  348. #else
  349.     *(long *) &(dl->data[n]) = AFTERVAL;
  350. #endif
  351.  
  352.     /* Add dl to start of allocation list       */
  353.     dl->next = mem_alloclist.next;
  354.     dl->prev = &mem_alloclist;
  355.     mem_alloclist.next = dl;
  356.     if (dl->next != NULL)
  357.     dl->next->prev = dl;
  358.  
  359.     mem_count++;
  360.     mem_numalloc += n;
  361.     if (mem_numalloc > mem_maxalloc)
  362.     mem_maxalloc = mem_numalloc;
  363.     return mem_dltoptr(dl);
  364. }
  365.  
  366. void mem_free_debug(ptr,fil,lin)
  367. void *ptr;
  368. char *fil;
  369. int lin;
  370. {
  371.     struct mem_debug *dl;
  372.  
  373.     if (ptr == NUL